home *** CD-ROM | disk | FTP | other *** search
/ Amiga Plus 2004 #11 / Amiga Plus CD - 2004 - No. 11.iso / AmiSoft / Comm / www / tidy_os4.lha / tidy / src / tidylib.c < prev    next >
C/C++ Source or Header  |  2004-07-25  |  39KB  |  1,603 lines

  1. /* tidylib.c -- internal library definitions
  2.  
  3.   (c) 1998-2004 (W3C) MIT, ERCIM, Keio University
  4.   See tidy.h for the copyright notice.
  5.  
  6.   CVS Info :
  7.  
  8.     $Author: hoehrmann $ 
  9.     $Date: 2004/06/03 14:25:24 $ 
  10.     $Revision: 1.44 $ 
  11.  
  12.   Defines HTML Tidy API implemented by tidy library.
  13.   
  14.   Very rough initial cut for discussion purposes.
  15.  
  16.   Public interface is const-correct and doesn't explicitly depend
  17.   on any globals.  Thus, thread-safety may be introduced w/out
  18.   changing the interface.
  19.  
  20.   Looking ahead to a C++ wrapper, C functions always pass 
  21.   this-equivalent as 1st arg.
  22.  
  23.   Created 2001-05-20 by Charles Reitzel
  24.  
  25. */
  26.  
  27. #include <errno.h>
  28.  
  29. #include "tidy-int.h"
  30. #include "parser.h"
  31. #include "clean.h"
  32. #include "config.h"
  33. #include "message.h"
  34. #include "pprint.h"
  35. #include "entities.h"
  36. #include "tmbstr.h"
  37. #include "utf8.h"
  38.  
  39. #ifdef TIDY_WIN32_MLANG_SUPPORT
  40. #include "win32tc.h"
  41. #endif
  42.  
  43. #ifdef NEVER
  44. TidyDocImpl* tidyDocToImpl( TidyDoc tdoc )
  45. {
  46.   return (TidyDocImpl*) tdoc;
  47. }
  48. TidyDoc      tidyImplToDoc( TidyDocImpl* impl )
  49. {
  50.   return (TidyDoc) impl;
  51. }
  52.  
  53. Node*        tidyNodeToImpl( TidyNode tnod )
  54. {
  55.   return (Node*) tnod;
  56. }
  57. TidyNode     tidyImplToNode( Node* node )
  58. {
  59.   return (TidyNode) node;
  60. }
  61.  
  62. AttVal*      tidyAttrToImpl( TidyAttr tattr )
  63. {
  64.   return (AttVal*) tattr;
  65. }
  66. TidyAttr     tidyImplToAttr( AttVal* attval )
  67. {
  68.   return (TidyAttr) attval;
  69. }
  70.  
  71. const TidyOptionImpl* tidyOptionToImpl( TidyOption topt )
  72. {
  73.   return (const TidyOptionImpl*) topt;
  74. }
  75. TidyOption   tidyImplToOption( const TidyOptionImpl* option )
  76. {
  77.   return (TidyOption) option;
  78. }
  79. #endif
  80.  
  81. /* Tidy public interface
  82. **
  83. ** Most functions return an integer:
  84. **
  85. ** 0    -> SUCCESS
  86. ** >0   -> WARNING
  87. ** <0   -> ERROR
  88. ** 
  89. */
  90.  
  91. TidyDoc       tidyCreate(void)
  92. {
  93.   TidyDocImpl* impl = tidyDocCreate();
  94.   return tidyImplToDoc( impl );
  95. }
  96.  
  97. void          tidyRelease( TidyDoc tdoc )
  98. {
  99.   TidyDocImpl* impl = tidyDocToImpl( tdoc );
  100.   tidyDocRelease( impl );
  101. }
  102.  
  103. TidyDocImpl* tidyDocCreate(void)
  104. {
  105.     TidyDocImpl* doc = (TidyDocImpl*)MemAlloc( sizeof(TidyDocImpl) );
  106.     ClearMemory( doc, sizeof(*doc) );
  107.  
  108.     InitMap();
  109.     InitTags( doc );
  110.     InitAttrs( doc );
  111.     InitConfig( doc );
  112.     InitPrintBuf( doc );
  113.  
  114.     /* By default, wire tidy messages to standard error.
  115.     ** Document input will be set by parsing routines.
  116.     ** Document output will be set by pretty print routines.
  117.     ** Config input will be set by config parsing routines.
  118.     ** But we need to start off with a way to report errors.
  119.     */
  120.     doc->errout = StdErrOutput();
  121.     return doc;
  122. }
  123.  
  124. void          tidyDocRelease( TidyDocImpl* doc )
  125. {
  126.     /* doc in/out opened and closed by parse/print routines */
  127.     if ( doc )
  128.     {
  129.         assert( doc->docIn == NULL );
  130.         assert( doc->docOut == NULL );
  131.  
  132.         ReleaseStreamOut( doc->errout );
  133.         doc->errout = NULL;
  134.  
  135.         FreePrintBuf( doc );
  136.         FreeLexer( doc );
  137.         FreeNode(doc, &doc->root);
  138.         ClearMemory(&doc->root, sizeof(Node));
  139.  
  140.         if (doc->givenDoctype)
  141.             MemFree(doc->givenDoctype);
  142.  
  143.         FreeConfig( doc );
  144.         FreeAttrTable( doc );
  145.         FreeTags( doc );
  146.         MemFree( doc );
  147.     }
  148. }
  149.  
  150. /* Let application store a chunk of data w/ each Tidy tdocance.
  151. ** Useful for callbacks.
  152. */
  153. void        tidySetAppData( TidyDoc tdoc, ulong appData )
  154. {
  155.   TidyDocImpl* impl = tidyDocToImpl( tdoc );
  156.   if ( impl )
  157.     impl->appData = appData;
  158. }
  159. ulong       tidyGetAppData( TidyDoc tdoc )
  160. {
  161.   TidyDocImpl* impl = tidyDocToImpl( tdoc );
  162.   if ( impl )
  163.     return impl->appData;
  164.   return 0;
  165. }
  166.  
  167. ctmbstr     tidyReleaseDate(void)
  168. {
  169.     return ReleaseDate();
  170. }
  171.  
  172.  
  173. /* Get/set configuration options
  174. */
  175. Bool        tidySetOptionCallback( TidyDoc tdoc, TidyOptCallback pOptCallback )
  176. {
  177.   TidyDocImpl* impl = tidyDocToImpl( tdoc );
  178.   if ( impl )
  179.   {
  180.     impl->pOptCallback = pOptCallback;
  181.     return yes;
  182.   }
  183.   return -EINVAL;
  184. }
  185.  
  186.  
  187. int     tidyLoadConfig( TidyDoc tdoc, ctmbstr cfgfil )
  188. {
  189.     TidyDocImpl* impl = tidyDocToImpl( tdoc );
  190.     if ( impl )
  191.         return ParseConfigFile( impl, cfgfil );
  192.     return -EINVAL;
  193. }
  194.  
  195. int     tidyLoadConfigEnc( TidyDoc tdoc, ctmbstr cfgfil, ctmbstr charenc )
  196. {
  197.     TidyDocImpl* impl = tidyDocToImpl( tdoc );
  198.     if ( impl )
  199.         return ParseConfigFileEnc( impl, cfgfil, charenc );
  200.     return -EINVAL;
  201. }
  202.  
  203. int         tidySetCharEncoding( TidyDoc tdoc, ctmbstr encnam )
  204. {
  205.     TidyDocImpl* impl = tidyDocToImpl( tdoc );
  206.     if ( impl )
  207.     {
  208.         int enc = CharEncodingId( encnam );
  209.         if ( enc >= 0 && AdjustCharEncoding(impl, enc) )
  210.             return 0;
  211.  
  212.         ReportBadArgument( impl, "char-encoding" );
  213.     }
  214.     return -EINVAL;
  215. }
  216.  
  217. int        tidySetInCharEncoding( TidyDoc tdoc, ctmbstr encnam )
  218. {
  219.     TidyDocImpl* impl = tidyDocToImpl( tdoc );
  220.     if ( impl )
  221.     {
  222.         int enc = CharEncodingId( encnam );
  223.         if ( enc >= 0 && SetOptionInt( impl, TidyInCharEncoding, enc ) )
  224.             return 0;
  225.  
  226.         ReportBadArgument( impl, "in-char-encoding" );
  227.     }
  228.     return -EINVAL;
  229. }
  230.  
  231. int        tidySetOutCharEncoding( TidyDoc tdoc, ctmbstr encnam )
  232. {
  233.     TidyDocImpl* impl = tidyDocToImpl( tdoc );
  234.     if ( impl )
  235.     {
  236.         int enc = CharEncodingId( encnam );
  237.         if ( enc >= 0 && SetOptionInt( impl, TidyOutCharEncoding, enc ) )
  238.             return 0;
  239.  
  240.         ReportBadArgument( impl, "out-char-encoding" );
  241.     }
  242.     return -EINVAL;
  243. }
  244.  
  245. TidyOptionId  tidyOptGetIdForName( ctmbstr optnam )
  246. {
  247.     const TidyOptionImpl* option = lookupOption( optnam );
  248.     if ( option )
  249.         return option->id;
  250.     return N_TIDY_OPTIONS;  /* Error */
  251. }
  252.  
  253. TidyIterator  tidyGetOptionList( TidyDoc tdoc )
  254. {
  255.     TidyDocImpl* impl = tidyDocToImpl( tdoc );
  256.     if ( impl )
  257.         return getOptionList( impl );
  258.     return (TidyIterator) -1;
  259. }
  260.  
  261. TidyOption    tidyGetNextOption( TidyDoc tdoc, TidyIterator* pos )
  262. {
  263.     TidyDocImpl* impl = tidyDocToImpl( tdoc );
  264.     const TidyOptionImpl* option = NULL;
  265.     if ( impl )
  266.         option = getNextOption( impl, pos );
  267.     else if ( pos )
  268.         *pos = 0;
  269.     return tidyImplToOption( option );
  270. }
  271.  
  272.  
  273. TidyOption    tidyGetOption( TidyDoc tdoc, TidyOptionId optId )
  274. {
  275. #pragma unused(tdoc)
  276.  
  277.     const TidyOptionImpl* option = getOption( optId );
  278.     return tidyImplToOption( option );
  279. }
  280. TidyOption    tidyGetOptionByName( TidyDoc doc, ctmbstr optnam )
  281. {
  282. #pragma unused(doc)
  283.  
  284.     const TidyOptionImpl* option = lookupOption( optnam );
  285.     return tidyImplToOption( option );
  286. }
  287.  
  288. TidyOptionId  tidyOptGetId( TidyOption topt )
  289. {
  290.     const TidyOptionImpl* option = tidyOptionToImpl( topt );
  291.     if ( option )
  292.         return option->id;
  293.     return N_TIDY_OPTIONS;
  294. }
  295. ctmbstr       tidyOptGetName( TidyOption topt )
  296. {
  297.     const TidyOptionImpl* option = tidyOptionToImpl( topt );
  298.     if ( option )
  299.         return option->name;
  300.     return NULL;
  301. }
  302. TidyOptionType tidyOptGetType( TidyOption topt )
  303. {
  304.     const TidyOptionImpl* option = tidyOptionToImpl( topt );
  305.     if ( option )
  306.         return option->type;
  307.     return (TidyOptionType) -1;
  308. }
  309. TidyConfigCategory tidyOptGetCategory( TidyOption topt )
  310. {
  311.     const TidyOptionImpl* option = tidyOptionToImpl( topt );
  312.     if ( option )
  313.         return option->category;
  314.     return (TidyConfigCategory) -1;
  315. }
  316. ctmbstr       tidyOptGetDefault( TidyOption topt )
  317. {
  318.     const TidyOptionImpl* option = tidyOptionToImpl( topt );
  319.     if ( option && option->type == TidyString )
  320.         return (ctmbstr) option->dflt;
  321.     return NULL;
  322. }
  323. ulong          tidyOptGetDefaultInt( TidyOption topt )
  324. {
  325.     const TidyOptionImpl* option = tidyOptionToImpl( topt );
  326.     if ( option && option->type != TidyString )
  327.         return option->dflt;
  328.     return ~0U;
  329. }
  330. Bool          tidyOptGetDefaultBool( TidyOption topt )
  331. {
  332.     const TidyOptionImpl* option = tidyOptionToImpl( topt );
  333.     if ( option && option->type != TidyString )
  334.         return ( option->dflt ? yes : no );
  335.     return no;
  336. }
  337. Bool          tidyOptIsReadOnly( TidyOption topt )
  338. {
  339.     const TidyOptionImpl* option = tidyOptionToImpl( topt );
  340.     if ( option  )
  341.         return ( option->parser == NULL );
  342.     return yes;
  343. }
  344.  
  345.  
  346. TidyIterator  tidyOptGetPickList( TidyOption topt )
  347. {
  348.     const TidyOptionImpl* option = tidyOptionToImpl( topt );
  349.     if ( option )
  350.       return getOptionPickList( option );
  351.     return (TidyIterator) -1;
  352. }
  353. ctmbstr       tidyOptGetNextPick( TidyOption topt, TidyIterator* pos )
  354. {
  355.     const TidyOptionImpl* option = tidyOptionToImpl( topt );
  356.     if ( option )
  357.         return getNextOptionPick( option, pos );
  358.     return NULL;
  359. }
  360.  
  361.  
  362. ctmbstr       tidyOptGetValue( TidyDoc tdoc, TidyOptionId optId )
  363. {
  364.   TidyDocImpl* impl = tidyDocToImpl( tdoc );
  365.   ctmbstr optval = NULL;
  366.   if ( impl )
  367.     optval = cfgStr( impl, optId );
  368.   return optval;
  369. }
  370. Bool        tidyOptSetValue( TidyDoc tdoc, TidyOptionId optId, ctmbstr val )
  371. {
  372.   TidyDocImpl* impl = tidyDocToImpl( tdoc );
  373.   if ( impl )
  374.     return ParseConfigValue( impl, optId, val );
  375.   return no;
  376. }
  377. Bool        tidyOptParseValue( TidyDoc tdoc, ctmbstr optnam, ctmbstr val )
  378. {
  379.   TidyDocImpl* impl = tidyDocToImpl( tdoc );
  380.   if ( impl )
  381.     return ParseConfigOption( impl, optnam, val );
  382.   return no;
  383. }
  384.  
  385. ulong        tidyOptGetInt( TidyDoc tdoc, TidyOptionId optId )
  386. {
  387.     TidyDocImpl* impl = tidyDocToImpl( tdoc );
  388.     ulong opti = 0;
  389.     if ( impl )
  390.         opti = cfg( impl, optId );
  391.     return opti;
  392. }
  393.  
  394. Bool        tidyOptSetInt( TidyDoc tdoc, TidyOptionId optId, ulong val )
  395. {
  396.     TidyDocImpl* impl = tidyDocToImpl( tdoc );
  397.     if ( impl )
  398.         return SetOptionInt( impl, optId, val );
  399.     return no;
  400. }
  401.  
  402. Bool         tidyOptGetBool( TidyDoc tdoc, TidyOptionId optId )
  403. {
  404.     TidyDocImpl* impl = tidyDocToImpl( tdoc );
  405.     Bool optb = no;
  406.     if ( impl )
  407.     {
  408.         const TidyOptionImpl* option = getOption( optId );
  409.         if ( option )
  410.         {
  411.             optb = cfgBool( impl, optId );
  412.         }
  413.     }
  414.     return optb;
  415. }
  416.  
  417. Bool        tidyOptSetBool( TidyDoc tdoc, TidyOptionId optId, Bool val )
  418. {
  419.     TidyDocImpl* impl = tidyDocToImpl( tdoc );
  420.     if ( impl )
  421.         return SetOptionBool( impl, optId, val );
  422.     return no;
  423. }
  424.  
  425. ctmbstr       tidyOptGetEncName( TidyDoc tdoc, TidyOptionId optId )
  426. {
  427.   uint enc = tidyOptGetInt( tdoc, optId );
  428.   return CharEncodingName( enc );
  429. }
  430.  
  431. ctmbstr       tidyOptGetCurrPick( TidyDoc tdoc, TidyOptionId optId )
  432. {
  433.     const TidyOptionImpl* option = getOption( optId );
  434.     if ( option && option->pickList )
  435.     {
  436.         uint ix, pick = tidyOptGetInt( tdoc, optId );
  437.         const ctmbstr* pL = option->pickList;
  438.         for ( ix=0; *pL && ix < pick; ++ix )
  439.             ++pL;
  440.         if ( *pL )
  441.             return *pL;
  442.     }
  443.     return NULL;
  444. }
  445.  
  446.  
  447. TidyIterator  tidyOptGetDeclTagList( TidyDoc tdoc )
  448. {
  449.     TidyDocImpl* impl = tidyDocToImpl( tdoc );
  450.     TidyIterator declIter = 0;
  451.     if ( impl )
  452.         declIter = GetDeclaredTagList( impl );
  453.     return declIter;
  454. }
  455.  
  456. ctmbstr       tidyOptGetNextDeclTag( TidyDoc tdoc, TidyOptionId optId,
  457.                                      TidyIterator* iter )
  458. {
  459.     TidyDocImpl* impl = tidyDocToImpl( tdoc );
  460.     ctmbstr tagnam = NULL;
  461.     if ( impl )
  462.     {
  463.         int tagtyp = 0;
  464.         if ( optId == TidyInlineTags )
  465.             tagtyp = tagtype_inline;
  466.         else if ( optId == TidyBlockTags )
  467.             tagtyp = tagtype_block;
  468.         else if ( optId == TidyEmptyTags )
  469.             tagtyp = tagtype_empty;
  470.         else if ( optId == TidyPreTags )
  471.             tagtyp = tagtype_pre;
  472.         if ( tagtyp )
  473.             tagnam = GetNextDeclaredTag( impl, tagtyp, iter );
  474.     }
  475.     return tagnam;
  476. }
  477.  
  478. int tidyOptSaveFile( TidyDoc tdoc, ctmbstr cfgfil )
  479. {
  480.     TidyDocImpl* impl = tidyDocToImpl( tdoc );
  481.     if ( impl )
  482.         return SaveConfigFile( impl, cfgfil );
  483.     return -EINVAL;
  484. }
  485.  
  486. int tidyOptSaveSink( TidyDoc tdoc, TidyOutputSink* sink )
  487. {
  488.     TidyDocImpl* impl = tidyDocToImpl( tdoc );
  489.     if ( impl )
  490.         return SaveConfigSink( impl, sink );
  491.     return -EINVAL;
  492. }
  493.  
  494. Bool tidyOptSnapshot( TidyDoc tdoc )
  495. {
  496.     TidyDocImpl* impl = tidyDocToImpl( tdoc );
  497.     if ( impl )
  498.     {
  499.         TakeConfigSnapshot( impl );
  500.         return yes;
  501.     }
  502.     return no;
  503. }
  504. Bool tidyOptResetToSnapshot( TidyDoc tdoc )
  505. {
  506.     TidyDocImpl* impl = tidyDocToImpl( tdoc );
  507.     if ( impl )
  508.     {
  509.         ResetConfigToSnapshot( impl );
  510.         return yes;
  511.     }
  512.     return no;
  513. }
  514. Bool tidyOptResetAllToDefault( TidyDoc tdoc )
  515. {
  516.     TidyDocImpl* impl = tidyDocToImpl( tdoc );
  517.     if ( impl )
  518.     {
  519.         ResetConfigToDefault( impl );
  520.         return yes;
  521.     }
  522.     return no;
  523. }
  524.  
  525. Bool tidyOptResetToDefault( TidyDoc tdoc, TidyOptionId optId )
  526. {
  527.     TidyDocImpl* impl = tidyDocToImpl( tdoc );
  528.     if ( impl )
  529.         return ResetOptionToDefault( impl, optId );
  530.     return no;
  531. }
  532.  
  533. Bool tidyOptDiffThanDefault( TidyDoc tdoc )
  534. {
  535.     TidyDocImpl* impl = tidyDocToImpl( tdoc );
  536.     if ( impl )
  537.         return ConfigDiffThanDefault( impl );
  538.     return no;
  539. }
  540. Bool          tidyOptDiffThanSnapshot( TidyDoc tdoc )
  541. {
  542.     TidyDocImpl* impl = tidyDocToImpl( tdoc );
  543.     if ( impl )
  544.         return ConfigDiffThanSnapshot( impl );
  545.     return no;
  546. }
  547.  
  548. Bool tidyOptCopyConfig( TidyDoc to, TidyDoc from )
  549. {
  550.     TidyDocImpl* docTo = tidyDocToImpl( to );
  551.     TidyDocImpl* docFrom = tidyDocToImpl( from );
  552.     if ( docTo && docFrom )
  553.     {
  554.         CopyConfig( docTo, docFrom );
  555.         return yes;
  556.     }
  557.     return no;
  558. }
  559.  
  560.  
  561. /* I/O and Message handling interface
  562. **
  563. ** By default, Tidy will define, create and use 
  564. ** tdocances of input and output handlers for 
  565. ** standard C buffered I/O (i.e. FILE* stdin,
  566. ** FILE* stdout and FILE* stderr for content
  567. ** input, content output and diagnostic output,
  568. ** respectively.  A FILE* cfgFile input handler
  569. ** will be used for config files.  Command line
  570. ** options will just be set directly.
  571. */
  572.  
  573. /* Use TidyReportFilter to filter messages by diagnostic level:
  574. ** info, warning, etc.  Just set diagnostic output 
  575. ** handler to redirect all diagnostics output.  Return true
  576. ** to proceed with output, false to cancel.
  577. */
  578. Bool        tidySetReportFilter( TidyDoc tdoc, TidyReportFilter filt )
  579. {
  580.   TidyDocImpl* impl = tidyDocToImpl( tdoc );
  581.   if ( impl )
  582.   {
  583.     impl->mssgFilt = filt;
  584.     return yes;
  585.   }
  586.   return -EINVAL;
  587. }
  588.  
  589. #if 0   /* Not yet */
  590. int         tidySetContentOutputSink( TidyDoc tdoc, TidyOutputSink* outp )
  591. {
  592.   TidyDocImpl* impl = tidyDocToImpl( tdoc );
  593.   if ( impl )
  594.   {
  595.     impl->docOut = outp;
  596.     return 0;
  597.   }
  598.   return -EINVAL;
  599. }
  600. int         tidySetDiagnosticOutputSink( TidyDoc tdoc, TidyOutputSink* outp )
  601. {
  602.   TidyDocImpl* impl = tidyDocToImpl( tdoc );
  603.   if ( impl )
  604.   {
  605.     impl->msgOut = outp;
  606.     return 0;
  607.   }
  608.   return -EINVAL;
  609. }
  610.  
  611.  
  612. /* Library helpers
  613. */
  614. cmbstr       tidyLookupMessage( TidyDoc tdoc, int errorNo )
  615. {
  616.   TidyDocImpl* impl = tidyDocToImpl( tdoc );
  617.   cmbstr mssg = NULL;
  618.   if ( impl )
  619.     mssg = tidyMessage_Lookup( impl->messages, errorNo );
  620.   return mssg;
  621. }
  622. #endif
  623.  
  624.  
  625. FILE*   tidySetErrorFile( TidyDoc tdoc, ctmbstr errfilnam )
  626. {
  627.     TidyDocImpl* impl = tidyDocToImpl( tdoc );
  628.     if ( impl )
  629.     {
  630.         FILE* errout = fopen( errfilnam, "wb" );
  631.         if ( errout )
  632.         {
  633.             uint outenc = cfg( impl, TidyOutCharEncoding );
  634.             uint nl = cfg( impl, TidyNewline );
  635.             ReleaseStreamOut( impl->errout );
  636.             impl->errout = FileOutput( errout, outenc, nl );
  637.             return errout;
  638.         }
  639.         else /* Emit message to current error sink */
  640.             FileError( impl, errfilnam, TidyError );
  641.     }
  642.     return NULL;
  643. }
  644.  
  645. int     tidySetErrorBuffer( TidyDoc tdoc, TidyBuffer* errbuf )
  646. {
  647.     TidyDocImpl* impl = tidyDocToImpl( tdoc );
  648.     if ( impl )
  649.     {
  650.         uint outenc = cfg( impl, TidyOutCharEncoding );
  651.         uint nl = cfg( impl, TidyNewline );
  652.         ReleaseStreamOut( impl->errout );
  653.         impl->errout = BufferOutput( errbuf, outenc, nl );
  654.         return ( impl->errout ? 0 : -ENOMEM );
  655.     }
  656.     return -EINVAL;
  657. }
  658.  
  659. int     tidySetErrorSink( TidyDoc tdoc, TidyOutputSink* sink )
  660. {
  661.     TidyDocImpl* impl = tidyDocToImpl( tdoc );
  662.     if ( impl )
  663.     {
  664.         uint outenc = cfg( impl, TidyOutCharEncoding );
  665.         uint nl = cfg( impl, TidyNewline );
  666.         ReleaseStreamOut( impl->errout );
  667.         impl->errout = UserOutput( sink, outenc, nl );
  668.         return ( impl->errout ? 0 : -ENOMEM );
  669.     }
  670.     return -EINVAL;
  671. }
  672.  
  673.  
  674. /* Document info */
  675. int         tidyStatus( TidyDoc tdoc )
  676. {
  677.     TidyDocImpl* impl = tidyDocToImpl( tdoc );
  678.     int tidyStat = -EINVAL;
  679.     if ( impl )
  680.         tidyStat = tidyDocStatus( impl );
  681.     return tidyStat;
  682. }
  683. int         tidyDetectedHtmlVersion( TidyDoc tdoc )
  684. {
  685. #pragma unused(tdoc)
  686.  
  687. /*    TidyDocImpl* impl = tidyDocToImpl( tdoc ); */
  688.     return 0;
  689. }
  690. Bool        tidyDetectedXhtml( TidyDoc tdoc )
  691. {
  692. #pragma unused(tdoc)
  693.  
  694. /*    TidyDocImpl* impl = tidyDocToImpl( tdoc ); */
  695.     return no;
  696. }
  697. Bool        tidyDetectedGenericXml( TidyDoc tdoc )
  698. {
  699. #pragma unused(tdoc)
  700.  
  701. /*    TidyDocImpl* impl = tidyDocToImpl( tdoc ); */
  702.     return no;
  703. }
  704.  
  705. uint        tidyErrorCount( TidyDoc tdoc )
  706. {
  707.     TidyDocImpl* impl = tidyDocToImpl( tdoc );
  708.     uint count = 0xFFFFFFFF;
  709.     if ( impl )
  710.         count = impl->errors;
  711.     return count;
  712. }
  713. uint        tidyWarningCount( TidyDoc tdoc )
  714. {
  715.     TidyDocImpl* impl = tidyDocToImpl( tdoc );
  716.     uint count = 0xFFFFFFFF;
  717.     if ( impl )
  718.         count = impl->warnings;
  719.     return count;
  720. }
  721. uint        tidyAccessWarningCount( TidyDoc tdoc )
  722. {
  723.     TidyDocImpl* impl = tidyDocToImpl( tdoc );
  724.     uint count = 0xFFFFFFFF;
  725.     if ( impl )
  726.         count = impl->accessErrors;
  727.     return count;
  728. }
  729. uint        tidyConfigErrorCount( TidyDoc tdoc )
  730. {
  731.     TidyDocImpl* impl = tidyDocToImpl( tdoc );
  732.     uint count = 0xFFFFFFFF;
  733.     if ( impl )
  734.         count = impl->optionErrors;
  735.     return count;
  736. }
  737.  
  738.  
  739. /* Error reporting functions 
  740. */
  741. void         tidyErrorSummary( TidyDoc tdoc )
  742. {
  743.     TidyDocImpl* impl = tidyDocToImpl( tdoc );
  744.     if ( impl )
  745.         ErrorSummary( impl );
  746. }
  747. void         tidyGeneralInfo( TidyDoc tdoc )
  748. {
  749.     TidyDocImpl* impl = tidyDocToImpl( tdoc );
  750.     if ( impl )
  751.         GeneralInfo( impl );
  752. }
  753.  
  754.  
  755. /* I/O Functions
  756. **
  757. ** Initial version supports only whole-file operations.
  758. ** Do not expose Tidy StreamIn or Out data structures - yet.
  759. */
  760.  
  761. /* Parse/load Functions
  762. **
  763. ** HTML/XHTML version determined from input.
  764. */
  765. int   tidyParseFile( TidyDoc tdoc, ctmbstr filnam )
  766. {
  767.     TidyDocImpl* doc = tidyDocToImpl( tdoc );
  768.     return tidyDocParseFile( doc, filnam );
  769. }
  770. int   tidyParseStdin( TidyDoc tdoc )
  771. {
  772.     TidyDocImpl* doc = tidyDocToImpl( tdoc );
  773.     return tidyDocParseStdin( doc );
  774. }
  775. int   tidyParseString( TidyDoc tdoc, ctmbstr content )
  776. {
  777.     TidyDocImpl* doc = tidyDocToImpl( tdoc );
  778.     return tidyDocParseString( doc, content );
  779. }
  780. int   tidyParseBuffer( TidyDoc tdoc, TidyBuffer* inbuf )
  781. {
  782.     TidyDocImpl* doc = tidyDocToImpl( tdoc );
  783.     return tidyDocParseBuffer( doc, inbuf );
  784. }
  785. int   tidyParseSource( TidyDoc tdoc, TidyInputSource* source )
  786. {
  787.     TidyDocImpl* doc = tidyDocToImpl( tdoc );
  788.     return tidyDocParseSource( doc, source );
  789. }
  790.  
  791.  
  792. int   tidyDocParseFile( TidyDocImpl* doc, ctmbstr filnam )
  793. {
  794.     int status = -ENOENT;
  795.     FILE* fin = fopen( filnam, "rb" );
  796.  
  797. #if PRESERVE_FILE_TIMES
  798.     struct stat sbuf = {0};
  799.     /* get last modified time */
  800.     ClearMemory( &doc->filetimes, sizeof(doc->filetimes) );
  801.     if ( fin && cfgBool(doc,TidyKeepFileTimes) &&
  802.          fstat(fileno(fin), &sbuf) != -1 )
  803.     {
  804.           doc->filetimes.actime  = sbuf.st_atime;
  805.           doc->filetimes.modtime = sbuf.st_mtime;
  806.     }
  807. #endif
  808.  
  809.     if ( fin )
  810.     {
  811.         StreamIn* in = FileInput( doc, fin, cfg( doc, TidyInCharEncoding ));
  812.         status = tidyDocParseStream( doc, in );
  813.         freeFileSource(&in->source, yes);
  814.         freeStreamIn(in);
  815.     }
  816.     else /* Error message! */
  817.         FileError( doc, filnam, TidyError );
  818.     return status;
  819. }
  820.  
  821. int   tidyDocParseStdin( TidyDocImpl* doc )
  822. {
  823.     StreamIn* in = FileInput( doc, stdin, cfg( doc, TidyInCharEncoding ));
  824.     int status = tidyDocParseStream( doc, in );
  825.     freeStreamIn(in);
  826.     return status;
  827. }
  828.  
  829. int   tidyDocParseBuffer( TidyDocImpl* doc, TidyBuffer* inbuf )
  830. {
  831.     int status = -EINVAL;
  832.     if ( inbuf )
  833.     {
  834.         StreamIn* in = BufferInput( doc, inbuf, cfg( doc, TidyInCharEncoding ));
  835.         status = tidyDocParseStream( doc, in );
  836.         freeStreamIn(in);
  837.     }
  838.     return status;
  839. }
  840.  
  841. int   tidyDocParseString( TidyDocImpl* doc, ctmbstr content )
  842. {
  843.     int status = -EINVAL;
  844.     TidyBuffer inbuf = {0};
  845.     StreamIn* in = NULL;
  846.  
  847.     if ( content )
  848.     {
  849.         tidyBufAttach( &inbuf, (void*)content, tmbstrlen(content)+1 );
  850.         in = BufferInput( doc, &inbuf, cfg( doc, TidyInCharEncoding ));
  851.         status = tidyDocParseStream( doc, in );
  852.         tidyBufDetach( &inbuf );
  853.         freeStreamIn(in);
  854.     }
  855.     return status;
  856. }
  857.  
  858. int   tidyDocParseSource( TidyDocImpl* doc, TidyInputSource* source )
  859. {
  860.     StreamIn* in = UserInput( doc, source, cfg( doc, TidyInCharEncoding ));
  861.     int status = tidyDocParseStream( doc, in );
  862.     freeStreamIn(in);
  863.     return status;
  864. }
  865.  
  866.  
  867. /* Print/save Functions
  868. **
  869. */
  870. int         tidySaveFile( TidyDoc tdoc, ctmbstr filnam )
  871. {
  872.     TidyDocImpl* doc = tidyDocToImpl( tdoc );
  873.     return tidyDocSaveFile( doc, filnam );
  874. }
  875. int         tidySaveStdout( TidyDoc tdoc )
  876. {
  877.     TidyDocImpl* doc = tidyDocToImpl( tdoc );
  878.     return tidyDocSaveStdout( doc );
  879. }
  880. int         tidySaveString( TidyDoc tdoc, tmbstr buffer, uint* buflen )
  881. {
  882.     TidyDocImpl* doc = tidyDocToImpl( tdoc );
  883.     return tidyDocSaveString( doc, buffer, buflen );
  884. }
  885. int         tidySaveBuffer( TidyDoc tdoc, TidyBuffer* outbuf )
  886. {
  887.     TidyDocImpl* doc = tidyDocToImpl( tdoc );
  888.     return tidyDocSaveBuffer( doc, outbuf );
  889. }
  890. int         tidySaveSink( TidyDoc tdoc, TidyOutputSink* sink )
  891. {
  892.     TidyDocImpl* doc = tidyDocToImpl( tdoc );
  893.     return tidyDocSaveSink( doc, sink );
  894. }
  895.  
  896. int         tidyDocSaveFile( TidyDocImpl* doc, ctmbstr filnam )
  897. {
  898.     int status = -ENOENT;
  899.     FILE* fout = NULL;
  900.  
  901.     /* Don't zap input file if no output */
  902.     if ( doc->errors > 0 &&
  903.          cfgBool(doc, TidyWriteBack) && !cfgBool(doc, TidyForceOutput) )
  904.         status = tidyDocStatus( doc );
  905.     else 
  906.         fout = fopen( filnam, "wb" );
  907.  
  908.     if ( fout )
  909.     {
  910.         uint outenc = cfg( doc, TidyOutCharEncoding );
  911.         uint nl = cfg( doc, TidyNewline );
  912.         StreamOut* out = FileOutput( fout, outenc, nl );
  913.  
  914.         status = tidyDocSaveStream( doc, out );
  915.  
  916.         fclose( fout );
  917.         MemFree( out );
  918.  
  919. #if PRESERVE_FILE_TIMES
  920.         if ( doc->filetimes.actime )
  921.         {
  922.             /* set file last accessed/modified times to original values */
  923.             utime( filnam, &doc->filetimes );
  924.             ClearMemory( &doc->filetimes, sizeof(doc->filetimes) );
  925.         }
  926. #endif /* PRESERVFILETIMES */
  927.     }
  928.     if ( status < 0 ) /* Error message! */
  929.         FileError( doc, filnam, TidyError );
  930.     return status;
  931. }
  932.  
  933.  
  934.  
  935. /* Note, _setmode() does NOT work on Win2K Pro w/ VC++ 6.0 SP3.
  936. ** The code has been left in in case it works w/ other compilers
  937. ** or operating systems.  If stdout is in Text mode, be aware that
  938. ** it will garble UTF16 documents.  In text mode, when it encounters
  939. ** a single byte of value 10 (0xA), it will insert a single byte 
  940. ** value 13 (0xD) just before it.  This has the effect of garbling
  941. ** the entire document.
  942. */
  943.  
  944. #if !defined(NO_SETMODE_SUPPORT)
  945.  
  946. #if defined(_WIN32) || defined(OS2_OS)
  947. #include <fcntl.h>
  948. #include <io.h>
  949. #endif
  950.  
  951. #endif
  952.  
  953. int         tidyDocSaveStdout( TidyDocImpl* doc )
  954. {
  955.     int oldstdoutmode = -1, oldstderrmode = -1, status = 0;
  956.     uint outenc = cfg( doc, TidyOutCharEncoding );
  957.     uint nl = cfg( doc, TidyNewline );
  958.     StreamOut* out = FileOutput( stdout, outenc, nl );
  959.  
  960. #if !defined(NO_SETMODE_SUPPORT)
  961.  
  962. #if defined(_WIN32) || defined(OS2_OS)
  963.     oldstdoutmode = setmode( fileno(stdout), _O_BINARY );
  964.     oldstderrmode = setmode( fileno(stderr), _O_BINARY );
  965. #endif
  966.  
  967. #endif
  968.  
  969.     if ( 0 == status )
  970.       status = tidyDocSaveStream( doc, out );
  971.  
  972.     fflush(stdout);
  973.     fflush(stderr);
  974.  
  975. #if !defined(NO_SETMODE_SUPPORT)
  976.  
  977. #if defined(_WIN32) || defined(OS2_OS)
  978.     if ( oldstdoutmode != -1 )
  979.         oldstdoutmode = setmode( fileno(stdout), oldstdoutmode );
  980.     if ( oldstderrmode != -1 )
  981.         oldstderrmode = setmode( fileno(stderr), oldstderrmode );
  982. #endif
  983.  
  984. #endif
  985.  
  986.     MemFree( out );
  987.     return status;
  988. }
  989.  
  990. int         tidyDocSaveString( TidyDocImpl* doc, tmbstr buffer, uint* buflen )
  991. {
  992.     uint outenc = cfg( doc, TidyOutCharEncoding );
  993.     uint nl = cfg( doc, TidyNewline );
  994.     TidyBuffer outbuf = {0};
  995.  
  996.     StreamOut* out = BufferOutput( &outbuf, outenc, nl );
  997.     int status = tidyDocSaveStream( doc, out );
  998.  
  999.     if ( outbuf.size > *buflen )
  1000.         status = -ENOMEM;
  1001.     else
  1002.         memcpy( buffer, outbuf.bp, outbuf.size );
  1003.  
  1004.     *buflen = outbuf.size;
  1005.     tidyBufFree( &outbuf );
  1006.     MemFree( out );
  1007.     return status;
  1008. }
  1009.  
  1010. int         tidyDocSaveBuffer( TidyDocImpl* doc, TidyBuffer* outbuf )
  1011. {
  1012.     int status = -EINVAL;
  1013.     if ( outbuf )
  1014.     {
  1015.         uint outenc = cfg( doc, TidyOutCharEncoding );
  1016.         uint nl = cfg( doc, TidyNewline );
  1017.         StreamOut* out = BufferOutput( outbuf, outenc, nl );
  1018.     
  1019.         status = tidyDocSaveStream( doc, out );
  1020.         MemFree( out );
  1021.     }
  1022.     return status;
  1023. }
  1024.  
  1025. int         tidyDocSaveSink( TidyDocImpl* doc, TidyOutputSink* sink )
  1026. {
  1027.     uint outenc = cfg( doc, TidyOutCharEncoding );
  1028.     uint nl = cfg( doc, TidyNewline );
  1029.     StreamOut* out = UserOutput( sink, outenc, nl );
  1030.     int status = tidyDocSaveStream( doc, out );
  1031.     MemFree( out );
  1032.     return status;
  1033. }
  1034.  
  1035. int         tidyDocStatus( TidyDocImpl* doc )
  1036. {
  1037.     if ( doc->errors > 0 )
  1038.         return 2;
  1039.     if ( doc->warnings > 0 || doc->accessErrors > 0 )
  1040.         return 1;
  1041.     return 0;
  1042. }
  1043.  
  1044.  
  1045.  
  1046. int         tidyCleanAndRepair( TidyDoc tdoc )
  1047. {
  1048.     TidyDocImpl* impl = tidyDocToImpl( tdoc );
  1049.     if ( impl )
  1050.       return tidyDocCleanAndRepair( impl );
  1051.     return -EINVAL;
  1052. }
  1053.  
  1054. int         tidyRunDiagnostics( TidyDoc tdoc )
  1055. {
  1056.     TidyDocImpl* impl = tidyDocToImpl( tdoc );
  1057.     if ( impl )
  1058.       return tidyDocRunDiagnostics( impl );
  1059.     return -EINVAL;
  1060. }
  1061.  
  1062.  
  1063. /* Workhorse functions.
  1064. **
  1065. ** Parse requires input source, all input config items 
  1066. ** and diagnostic sink to have all been set before calling.
  1067. **
  1068. ** Emit likewise requires that document sink and all
  1069. ** pretty printing options have been set.
  1070. */
  1071. static ctmbstr integrity = "\nPanic - tree has lost its integrity\n";
  1072.  
  1073. int         tidyDocParseStream( TidyDocImpl* doc, StreamIn* in )
  1074. {
  1075.     Bool xmlIn = cfgBool( doc, TidyXmlTags );
  1076.     int bomEnc;
  1077.  
  1078.     assert( doc != NULL && in != NULL );
  1079.     assert( doc->docIn == NULL );
  1080.     doc->docIn = in;
  1081.  
  1082.     TakeConfigSnapshot( doc );    /* Save config state */
  1083.     FreeLexer( doc );
  1084.     FreeAnchors( doc );
  1085.  
  1086.     FreeNode(doc, &doc->root);
  1087.     ClearMemory(&doc->root, sizeof(Node));
  1088.  
  1089.     if (doc->givenDoctype)
  1090.         MemFree(doc->givenDoctype);
  1091.  
  1092.     doc->givenDoctype = NULL;
  1093.  
  1094.     doc->lexer = NewLexer( doc );
  1095.     /* doc->lexer->root = &doc->root; */
  1096.     doc->root.line = doc->lexer->lines;
  1097.     doc->root.column = doc->lexer->columns;
  1098.     doc->inputHadBOM = no;
  1099.  
  1100.     bomEnc = ReadBOMEncoding(in);
  1101.  
  1102.     if (bomEnc != -1)
  1103.     {
  1104.         in->encoding = bomEnc;
  1105.         SetOptionInt(doc, TidyInCharEncoding, bomEnc);
  1106.     }
  1107.  
  1108. #ifdef TIDY_WIN32_MLANG_SUPPORT
  1109.     if (in->encoding > WIN32MLANG)
  1110.         Win32MLangInitInputTranscoder(in, in->encoding);
  1111. #endif /* TIDY_WIN32_MLANG_SUPPORT */
  1112.  
  1113.     /* Tidy doesn't alter the doctype for generic XML docs */
  1114.     if ( xmlIn )
  1115.     {
  1116.         ParseXMLDocument( doc );
  1117.         if ( !CheckNodeIntegrity( &doc->root ) )
  1118.             FatalError( integrity );
  1119.     }
  1120.     else
  1121.     {
  1122.         doc->warnings = 0;
  1123.         ParseDocument( doc );
  1124.         if ( !CheckNodeIntegrity( &doc->root ) )
  1125.             FatalError( integrity );
  1126.     }
  1127.  
  1128. #ifdef TIDY_WIN32_MLANG_SUPPORT
  1129.     Win32MLangUninitInputTranscoder(in);
  1130. #endif /* TIDY_WIN32_MLANG_SUPPORT */
  1131.  
  1132.     doc->docIn = NULL;
  1133.     return tidyDocStatus( doc );
  1134. }
  1135.  
  1136. int         tidyDocRunDiagnostics( TidyDocImpl* doc )
  1137. {
  1138.     uint acclvl = cfg( doc, TidyAccessibilityCheckLevel );
  1139.     Bool quiet = cfgBool( doc, TidyQuiet );
  1140.     Bool force = cfgBool( doc, TidyForceOutput );
  1141.  
  1142.     if ( !quiet )
  1143.     {
  1144.  
  1145.         ReportMarkupVersion( doc );
  1146.         ReportNumWarnings( doc );
  1147.     }
  1148.     
  1149.     if ( doc->errors > 0 && !force )
  1150.         NeedsAuthorIntervention( doc );
  1151.  
  1152. #if SUPPORT_ACCESSIBILITY_CHECKS
  1153.      if ( acclvl > 0 )
  1154.          AccessibilityChecks( doc );
  1155. #endif
  1156.  
  1157.      return tidyDocStatus( doc );
  1158. }
  1159.  
  1160. int         tidyDocCleanAndRepair( TidyDocImpl* doc )
  1161. {
  1162.     Bool word2K   = cfgBool( doc, TidyWord2000 );
  1163.     Bool logical  = cfgBool( doc, TidyLogicalEmphasis );
  1164.     Bool clean    = cfgBool( doc, TidyMakeClean );
  1165.     Bool dropFont = cfgBool( doc, TidyDropFontTags );
  1166.     Bool htmlOut  = cfgBool( doc, TidyHtmlOut );
  1167.     Bool xmlOut   = cfgBool( doc, TidyXmlOut );
  1168.     Bool xhtmlOut = cfgBool( doc, TidyXhtmlOut );
  1169.     Bool xmlDecl  = cfgBool( doc, TidyXmlDecl );
  1170.     Bool tidyMark = cfgBool( doc, TidyMark );
  1171.     Node* node;
  1172.  
  1173.     /* simplifies <b><b> ... </b> ...</b> etc. */
  1174.     NestedEmphasis( doc, &doc->root );
  1175.  
  1176.     /* cleans up <dir>indented text</dir> etc. */
  1177.     List2BQ( doc, &doc->root );
  1178.     BQ2Div( doc, &doc->root );
  1179.  
  1180.     /* replaces i by em and b by strong */
  1181.     if ( logical )
  1182.         EmFromI( doc, &doc->root );
  1183.  
  1184.     if ( word2K && IsWord2000(doc) )
  1185.     {
  1186.         /* prune Word2000's <![if ...]> ... <![endif]> */
  1187.         DropSections( doc, &doc->root );
  1188.  
  1189.         /* drop style & class attributes and empty p, span elements */
  1190.         CleanWord2000( doc, &doc->root );
  1191.     }
  1192.  
  1193.     /* replaces presentational markup by style rules */
  1194.     if ( clean || dropFont )
  1195.         CleanDocument( doc );
  1196.  
  1197.     /*  Move terminating <br /> tags from out of paragraphs  */
  1198.     /*!  Do we want to do this for all block-level elements?  */
  1199.  
  1200.     /* This is disabled due to http://tidy.sf.net/bug/681116 */
  1201. #if 0
  1202.     FixBrakes( doc, FindBody( doc ));
  1203. #endif
  1204.  
  1205.     /*  Reconcile http-equiv meta element with output encoding  */
  1206.     if (cfg( doc, TidyOutCharEncoding) != RAW
  1207. #ifndef NO_NATIVE_ISO2022_SUPPORT
  1208.         && cfg( doc, TidyOutCharEncoding) != ISO2022
  1209. #endif
  1210.         )
  1211.         VerifyHTTPEquiv( doc, FindHEAD( doc ));
  1212.  
  1213.     if ( !CheckNodeIntegrity( &doc->root ) )
  1214.         FatalError( integrity );
  1215.  
  1216.     /* remember given doctype for reporting */
  1217.     node = FindDocType(doc);
  1218.     if (node)
  1219.     {
  1220.         AttVal* fpi = GetAttrByName(node, "PUBLIC");
  1221.         if (AttrHasValue(fpi))
  1222.             doc->givenDoctype = tmbstrdup(fpi->value);
  1223.     }
  1224.  
  1225.     if ( doc->root.content )
  1226.     {
  1227.         /* If we had XHTML input but want HTML output */
  1228.         if ( htmlOut && doc->lexer->isvoyager )
  1229.         {
  1230.             Node* node = FindDocType(doc);
  1231.             /* Remove reference, but do not free */
  1232.             if (node)
  1233.               RemoveNode(node);
  1234.         }
  1235.  
  1236.         if (xhtmlOut && !htmlOut)
  1237.         {
  1238.             SetXHTMLDocType(doc);
  1239.             FixAnchors(doc, &doc->root, yes, yes, yes);
  1240.             FixXhtmlNamespace(doc, yes);
  1241.             FixLanguageInformation(doc, &doc->root, yes, yes);
  1242.         }
  1243.         else
  1244.         {
  1245.             FixDocType(doc);
  1246.             FixAnchors(doc, &doc->root, yes, yes, no);
  1247.             FixXhtmlNamespace(doc, no);
  1248.             FixLanguageInformation(doc, &doc->root, no, yes);
  1249.         }
  1250.  
  1251.         if (tidyMark )
  1252.             AddGenerator(doc);
  1253.     }
  1254.  
  1255.     /* ensure presence of initial <?XML version="1.0"?> */
  1256.     if ( xmlOut && xmlDecl )
  1257.         FixXmlDecl( doc );
  1258.  
  1259.     return tidyDocStatus( doc );
  1260. }
  1261.  
  1262. int         tidyDocSaveStream( TidyDocImpl* doc, StreamOut* out )
  1263. {
  1264.     Bool showMarkup  = cfgBool( doc, TidyShowMarkup );
  1265.     Bool forceOutput = cfgBool( doc, TidyForceOutput );
  1266. #if SUPPORT_UTF16_ENCODINGS
  1267.     Bool outputBOM   = ( cfg(doc, TidyOutputBOM) == yes );
  1268.     Bool smartBOM    = ( cfg(doc, TidyOutputBOM) == TidyAutoState );
  1269. #endif
  1270.     Bool xmlOut      = cfgBool( doc, TidyXmlOut );
  1271.     Bool xhtmlOut    = cfgBool( doc, TidyXhtmlOut );
  1272.     Bool bodyOnly    = cfgBool( doc, TidyBodyOnly );
  1273.  
  1274.     Bool dropComments = cfgBool(doc, TidyHideComments);
  1275.     Bool makeClean    = cfgBool(doc, TidyMakeClean);
  1276.     Bool asciiChars   = cfgBool(doc, TidyAsciiChars);
  1277.     Bool makeBare     = cfgBool(doc, TidyMakeBare);
  1278.     Bool escapeCDATA  = cfgBool(doc, TidyEscapeCdata);
  1279.  
  1280.     if (escapeCDATA)
  1281.         ConvertCDATANodes(doc, &doc->root);
  1282.  
  1283.     if (dropComments)
  1284.         DropComments(doc, &doc->root);
  1285.  
  1286.     if (makeClean)
  1287.     {
  1288.         /* noop */
  1289.         DropFontElements(doc, &doc->root, NULL);
  1290.         WbrToSpace(doc, &doc->root);
  1291.     }
  1292.  
  1293.     if ((makeClean && asciiChars) || makeBare)
  1294.         DowngradeTypography(doc, &doc->root);
  1295.  
  1296.     if (makeBare)
  1297.         /* Note: no longer replaces   in */
  1298.         /* attribute values / non-text tokens */
  1299.         NormalizeSpaces(doc->lexer, &doc->root);
  1300.     else
  1301.         ReplacePreformattedSpaces(doc, &doc->root);
  1302.  
  1303.     if ( showMarkup && (doc->errors == 0 || forceOutput) )
  1304.     {
  1305. #if SUPPORT_UTF16_ENCODINGS
  1306.         /* Output a Byte Order Mark if required */
  1307.         if ( outputBOM || (doc->inputHadBOM && smartBOM) )
  1308.             outBOM( out );
  1309. #endif
  1310.  
  1311.         /* No longer necessary. No DOCTYPE == HTML 3.2,
  1312.         ** which gives you only the basic character entities,
  1313.         ** which are safe in any browser.
  1314.         ** if ( !FindDocType(doc) )
  1315.         **    SetOptionBool( doc, TidyNumEntities, yes );
  1316.         */
  1317.  
  1318.         doc->docOut = out;
  1319.         if ( xmlOut && !xhtmlOut )
  1320.             PPrintXMLTree( doc, 0, 0, &doc->root );
  1321.         else if ( bodyOnly )
  1322.             PrintBody( doc );
  1323.         else
  1324.             PPrintTree( doc, 0, 0, &doc->root );
  1325.  
  1326.         PFlushLine( doc, 0 );
  1327.         doc->docOut = NULL;
  1328.     }
  1329.  
  1330.     ResetConfigToSnapshot( doc );
  1331.     return tidyDocStatus( doc );
  1332. }
  1333.  
  1334. /* Tree traversal functions
  1335. **
  1336. ** The big issue here is the degree to which we should mimic
  1337. ** a DOM and/or SAX nodes.
  1338. ** 
  1339. ** Is it 100% possible (and, if so, how difficult is it) to 
  1340. ** emit SAX events from this API?  If SAX events are possible,
  1341. ** is that 100% of data needed to build a DOM?
  1342. */
  1343.  
  1344. TidyNode    tidyGetRoot( TidyDoc tdoc )
  1345. {
  1346.     TidyDocImpl* impl = tidyDocToImpl( tdoc );
  1347.     return tidyImplToNode( &impl->root );
  1348. }
  1349.  
  1350. TidyNode    tidyGetHtml( TidyDoc tdoc )
  1351. {
  1352.   TidyDocImpl* impl = tidyDocToImpl( tdoc );
  1353.   Node* node = NULL;
  1354.   if ( impl )
  1355.       node = FindHTML( impl );
  1356.   return tidyImplToNode( node );
  1357. }
  1358.  
  1359. TidyNode    tidyGetHead( TidyDoc tdoc )
  1360. {
  1361.   TidyDocImpl* impl = tidyDocToImpl( tdoc );
  1362.   Node* node = NULL;
  1363.   if ( impl )
  1364.       node = FindHEAD( impl );
  1365.   return tidyImplToNode( node );
  1366. }
  1367.  
  1368. TidyNode    tidyGetBody( TidyDoc tdoc )
  1369. {
  1370.   TidyDocImpl* impl = tidyDocToImpl( tdoc );
  1371.   Node* node = NULL;
  1372.   if ( impl )
  1373.       node = FindBody( impl );
  1374.   return tidyImplToNode( node );
  1375. }
  1376.  
  1377. /* parent / child */
  1378. TidyNode    tidyGetParent( TidyNode tnod )
  1379. {
  1380.   Node* nimp = tidyNodeToImpl( tnod );
  1381.   return tidyImplToNode( nimp->parent );
  1382. }
  1383. TidyNode    tidyGetChild( TidyNode tnod )
  1384. {
  1385.   Node* nimp = tidyNodeToImpl( tnod );
  1386.   return tidyImplToNode( nimp->content );
  1387. }
  1388.  
  1389. /* siblings */
  1390. TidyNode    tidyGetNext( TidyNode tnod )
  1391. {
  1392.   Node* nimp = tidyNodeToImpl( tnod );
  1393.   return tidyImplToNode( nimp->next );
  1394. }
  1395. TidyNode    tidyGetPrev( TidyNode tnod )
  1396. {
  1397.   Node* nimp = tidyNodeToImpl( tnod );
  1398.   return tidyImplToNode( nimp->prev );
  1399. }
  1400.  
  1401. /* Node info */
  1402. TidyNodeType tidyNodeGetType( TidyNode tnod )
  1403. {
  1404.   Node* nimp = tidyNodeToImpl( tnod );
  1405.   TidyNodeType ntyp = TidyNode_Root;
  1406.   if ( nimp )
  1407.     ntyp = (TidyNodeType) nimp->type;
  1408.   return ntyp;
  1409. }
  1410.  
  1411. uint tidyNodeLine( TidyNode tnod )
  1412. {
  1413.   Node* nimp = tidyNodeToImpl( tnod );
  1414.   uint line = 0;
  1415.   if ( nimp )
  1416.     line = nimp->line;
  1417.   return line;
  1418. }
  1419. uint tidyNodeColumn( TidyNode tnod )
  1420. {
  1421.   Node* nimp = tidyNodeToImpl( tnod );
  1422.   uint col = 0;
  1423.   if ( nimp )
  1424.     col = nimp->column;
  1425.   return col;
  1426. }
  1427.  
  1428. ctmbstr        tidyNodeGetName( TidyNode tnod )
  1429. {
  1430.   Node* nimp = tidyNodeToImpl( tnod );
  1431.   ctmbstr nnam = NULL;
  1432.   if ( nimp )
  1433.     nnam = nimp->element;
  1434.   return nnam;
  1435. }
  1436.  
  1437.  
  1438. Bool  tidyNodeHasText( TidyDoc tdoc, TidyNode tnod )
  1439. {
  1440.   TidyDocImpl* doc = tidyDocToImpl( tdoc );
  1441.   if ( doc )
  1442.       return nodeHasText( doc, tidyNodeToImpl(tnod) );
  1443.   return no;
  1444. }
  1445.  
  1446.  
  1447. Bool  tidyNodeGetText( TidyDoc tdoc, TidyNode tnod, TidyBuffer* outbuf )
  1448. {
  1449.   TidyDocImpl* doc = tidyDocToImpl( tdoc );
  1450.   Node* nimp = tidyNodeToImpl( tnod );
  1451.   if ( doc && nimp && outbuf )
  1452.   {
  1453.       uint outenc     = cfg( doc, TidyOutCharEncoding );
  1454.       uint nl         = cfg( doc, TidyNewline );
  1455.       StreamOut* out  = BufferOutput( outbuf, outenc, nl );
  1456.       Bool xmlOut     = cfgBool( doc, TidyXmlOut );
  1457.       Bool xhtmlOut   = cfgBool( doc, TidyXhtmlOut );
  1458.  
  1459.       doc->docOut = out;
  1460.       if ( xmlOut && !xhtmlOut )
  1461.           PPrintXMLTree( doc, 0, 0, nimp );
  1462.       else
  1463.           PPrintTree( doc, 0, 0, nimp );
  1464.  
  1465.       PFlushLine( doc, 0 );
  1466.       doc->docOut = NULL;
  1467.   
  1468.       MemFree( out );
  1469.       return yes;
  1470.   }
  1471.   return no;
  1472. }
  1473.  
  1474.  
  1475. Bool tidyNodeIsProp( TidyDoc tdoc, TidyNode tnod )
  1476. {
  1477. #pragma unused(tdoc)
  1478.  
  1479.   Node* nimp = tidyNodeToImpl( tnod );
  1480.   Bool isProprietary = yes;
  1481.   if ( nimp )
  1482.   {
  1483.     switch ( nimp->type )
  1484.     {
  1485.     case RootNode:
  1486.     case DocTypeTag:
  1487.     case CommentTag:
  1488.     case XmlDecl:
  1489.     case ProcInsTag:
  1490.     case TextNode:
  1491.     case CDATATag:
  1492.         isProprietary = no;
  1493.         break;
  1494.  
  1495.     case SectionTag:
  1496.     case AspTag:
  1497.     case JsteTag:
  1498.     case PhpTag:
  1499.         isProprietary = yes;
  1500.         break;
  1501.  
  1502.     case StartTag:
  1503.     case EndTag:
  1504.     case StartEndTag:
  1505.         isProprietary = ( nimp->tag
  1506.                           ? (nimp->tag->versions&VERS_PROPRIETARY)!=0
  1507.                           : yes );
  1508.         break;
  1509.     }
  1510.   }
  1511.   return isProprietary;
  1512. }
  1513.  
  1514. TidyTagId tidyNodeGetId(TidyNode tnod)
  1515. {
  1516.     Node* nimp = tidyNodeToImpl(tnod);
  1517.  
  1518.     TidyTagId tagId = TidyTag_UNKNOWN;
  1519.     if (nimp && nimp->tag)
  1520.         tagId = nimp->tag->id;
  1521.  
  1522.     return tagId;
  1523. }
  1524.  
  1525.  
  1526. /* Null for non-element nodes and all pure HTML
  1527. cmbstr       tidyNodeNsLocal( TidyNode tnod )
  1528. {
  1529. }
  1530. cmbstr       tidyNodeNsPrefix( TidyNode tnod )
  1531. {
  1532. }
  1533. cmbstr       tidyNodeNsUri( TidyNode tnod )
  1534. {
  1535. }
  1536. */
  1537.  
  1538. /* Iterate over attribute values */
  1539. TidyAttr    tidyAttrFirst( TidyNode tnod )
  1540. {
  1541.   Node* nimp = tidyNodeToImpl( tnod );
  1542.   AttVal* attval = NULL;
  1543.   if ( nimp )
  1544.     attval = nimp->attributes;
  1545.   return tidyImplToAttr( attval );
  1546. }
  1547. TidyAttr    tidyAttrNext( TidyAttr tattr )
  1548. {
  1549.   AttVal* attval = tidyAttrToImpl( tattr );
  1550.   AttVal* nxtval = NULL;
  1551.   if ( attval )
  1552.     nxtval = attval->next;
  1553.   return tidyImplToAttr( nxtval );
  1554. }
  1555.  
  1556. ctmbstr       tidyAttrName( TidyAttr tattr )
  1557. {
  1558.   AttVal* attval = tidyAttrToImpl( tattr );
  1559.   ctmbstr anam = NULL;
  1560.   if ( attval )
  1561.     anam = attval->attribute;
  1562.   return anam;
  1563. }
  1564. ctmbstr       tidyAttrValue( TidyAttr tattr )
  1565. {
  1566.   AttVal* attval = tidyAttrToImpl( tattr );
  1567.   ctmbstr aval = NULL;
  1568.   if ( attval )
  1569.     aval = attval->value;
  1570.   return aval;
  1571. }
  1572.  
  1573. /* Null for pure HTML
  1574. ctmbstr       tidyAttrNsLocal( TidyAttr tattr )
  1575. {
  1576. }
  1577. ctmbstr       tidyAttrNsPrefix( TidyAttr tattr )
  1578. {
  1579. }
  1580. ctmbstr       tidyAttrNsUri( TidyAttr tattr )
  1581. {
  1582. }
  1583. */
  1584.  
  1585. TidyAttrId tidyAttrGetId( TidyAttr tattr )
  1586. {
  1587.   AttVal* attval = tidyAttrToImpl( tattr );
  1588.   TidyAttrId attrId = TidyAttr_UNKNOWN;
  1589.   if ( attval && attval->dict )
  1590.     attrId = attval->dict->id;
  1591.   return attrId;
  1592. }
  1593. Bool tidyAttrIsProp( TidyAttr tattr )
  1594. {
  1595.   AttVal* attval = tidyAttrToImpl( tattr );
  1596.   Bool isProprietary = yes;
  1597.   if ( attval )
  1598.     isProprietary = ( attval->dict 
  1599.                       ? (attval->dict->versions & VERS_PROPRIETARY) != 0
  1600.                       : yes );
  1601.   return isProprietary;
  1602. }
  1603.